#include "Dragon.h"
#include "Player.h"
#include "DestroyGameObjectMessage.h"
#include "../SGD Wrappers/SGD_GraphicsManager.h"
#include "GameplayState.h"
#include "Game.h"
#include "Boss.h"
#include "CreatePortalMessage.h"
#include "TileSystem.h"
#include "CreateBulletMessage.h"
#include "Projectile.h"
#include "../SGD Wrappers/SGD_AudioManager.h"

Dragon::Dragon()
{
	StartAnimation("dragonwalking");
	//RegisterForEvent("");
	useGravity = true;

	SetLevel(GameplayState::GetInstance()->GetCurrLevel());
}

Dragon::~Dragon()
{
	//if (GetAugment())
	//{
	//	DestroyGameObjectMessage *msg = new DestroyGameObjectMessage{ GetAugment() };
	//	msg->SendMessageNow();
	//}
}

void Dragon::Update(float elapsedTime)
{
	dt = elapsedTime;

	Enemy::Update(elapsedTime);
	if (!updating) return;

	float distToPlayer = GameplayState::GetInstance()->GetPlayer()->GetPosition().x - GetPosition().x;

	aiming.x = distToPlayer < 0 ? -1.0f : 1.0f;

	if (currAttackStrat == FLYING) flightTime -= elapsedTime;
	else takeOffTimer -= elapsedTime;

	fireballTimer += elapsedTime;
}

void Dragon::Render()
{
	if (SGD::InputManager::GetInstance()->IsKeyDown(SGD::Key::F4))
		m_iHealth = 0;

	Boss::Render();
	AnimationSystem::GetInstance()->Render({ GetPosition().x - Game::GetInstance()->GetCameraPos().x, GetPosition().y - Game::GetInstance()->GetCameraPos().y }, animInfo);
}

/*virtual*/ bool Dragon::DoAttack()
{
	return ((GameplayState::GetInstance()->GetPlayer()->GetPosition() - m_ptPosition).ComputeLength() < 800.0f);
}

/*virtual*/ void Dragon::Attack()
{
	GameplayState *gameplay = GameplayState::GetInstance();
	SGD::Point playerPos = gameplay->GetPlayer()->GetPosition();
	float playerTop = gameplay->GetPlayer()->GetRect().top;
	float distToPlayer = (playerPos - m_ptPosition).ComputeLength();
	TileSystem *TS = TileSystem::GetInstance();

	//Decide when to take off
	if (takeOffTimer <= 0.0f) EnterFlying();

	//Control movement
	if (currAttackStrat != FLYING)
	{
		if (distToPlayer < 200)
			moveTimer -= dt;

		if (distToPlayer > 45.0f && moveTimer <= 0.0f)
		{
			MoveTowardsPlayer();
		}
		else
		{
			//If in melee range of player
			if (currAttackStrat != MELEE)
			{
				currAttackStrat = MELEE;
				StartAnimation("dragonbiting");
			}

			m_vtVelocity.x = 0.0f;
		}
	}
	else if (currAttackStrat == FLYING)
	{
		float angle = SGD::Vector{ 1, 0 }.ComputeAngle((playerPos - m_ptPosition).ComputeNormalized());
		if (!patrolDirectionRight) angle = SGD::Vector{ -1, 0 }.ComputeAngle((playerPos - m_ptPosition).ComputeNormalized());

		bool dive = false;
		if (patrolDirectionRight && playerPos.x > m_ptPosition.x && abs(angle - SGD::PI / 4) < 0.2f)
			dive = true;
		else if (!patrolDirectionRight && playerPos.x < m_ptPosition.x && abs(angle - SGD::PI / 4) < 0.2f)
			dive = true;

		//If diving then do the motion and return
		if (dive)
		{
			SGD::Vector toPlayer = playerPos - m_ptPosition;
			toPlayer.Normalize();
			toPlayer *= 200;
			m_vtVelocity = toPlayer;

			return;
		}

		//Rain fireballs from above
		if (fireballTimer > 1.0f && ((patrolDirectionRight && playerPos.x > m_ptPosition.x) || (!patrolDirectionRight && playerPos.x < m_ptPosition.x)))
		{
			fireballTimer = 0.0f;

			CreateBulletMessage * Msg = new CreateBulletMessage{ this, RotationToPlayer(), false };
			Msg->QueueMessage();
		}

		//Decide when to stop flying
		if (flightTime <= 0.0f) EnterLand();

		if (!patrolDirectionRight)
		{
			//to the left
			bool leftWall = TS->CheckCollison(gameplay->GetMapIndex(), { GetRect().left - 10, GetPosition().y });
			if (playerPos.x - m_ptPosition.x > 200.0f || leftWall)
				patrolDirectionRight = true;
			else MoveLeft();
		}
		else
		{
			bool rightWall = TS->CheckCollison(gameplay->GetMapIndex(), { GetRect().right + 10, GetPosition().y });
			if (m_ptPosition.x - playerPos.x > 200.0f || rightWall)
				patrolDirectionRight = false;
			else MoveRight();
		}

		//Also try to go up above player
		float targetHeight = playerTop - 100.0f;
		bool ceiling = TS->CheckCollison(gameplay->GetMapIndex(), { GetPosition().x, GetRect().top - 50 });
		bool floor = TS->CheckCollison(gameplay->GetMapIndex(), { GetPosition().x, GetRect().bottom + 50 });
		if (m_ptPosition.y < targetHeight && !floor)
		{
			m_vtVelocity.y = 70;
		}
		else if (!ceiling)
		{
			m_vtVelocity.y = -70;
		}
	}
}

void Dragon::EnterFlying()
{
	if (currAttackStrat == FLYING) return;

	StartAnimation("dragonflying");
	useGravity = false;
	currAttackStrat = FLYING;
	flightTime = (rand() % 5) + 10.0f;
}

void Dragon::EnterLand()
{
	StartAnimation("dragonwalking");
	useGravity = true;
	currAttackStrat = GROUND;
	EnterIdle();
	takeOffTimer = (rand() % 10) + 10.0f;
}

void Dragon::MoveTowardsPlayer()
{
	GameplayState *gameplay = GameplayState::GetInstance();
	SGD::Point playerPos = gameplay->GetPlayer()->GetPosition();

	if (currAttackStrat != GROUND)
	{
		currAttackStrat = GROUND;
		StartAnimation("dragonwalking");
	}

	//Move towards player
	if (playerPos.x < m_ptPosition.x)
		MoveLeft();
	else
		MoveRight();
}

/*virtual*/ void Dragon::MoveLeft(float speed)
{
	if (currAttackStrat == FLYING)
	{
		m_vtVelocity = { 0.0f, 0.0f };
		Enemy::MoveLeft(speed);
	}
	else
		Enemy::MoveLeft(speed);
}

/*virtual*/ void Dragon::MoveRight(float speed)
{
	if (currAttackStrat == FLYING)
	{
		m_vtVelocity = { 0.0f, 0.0f };
		Enemy::MoveRight(speed);
	}
	else
		Enemy::MoveRight(speed);
}

/*virtual*/ void Dragon::EnterIdle()
{
	if (state == State::IDLE) return;
	Enemy::EnterIdle();

	StartAnimation("dragonwalking");
}

/*virtual*/ void Dragon::EnterCloseIn()
{
	if (state == State::CLOSEIN) return;
	Enemy::EnterCloseIn();

	StartAnimation("dragonwalking");
}

/*virtual*/ void Dragon::EnterDead()
{
	if (state == State::DEAD) return;
	Enemy::EnterDead();

	GameplayState::GetInstance()->GetPlayer()->SetMinPosInWorld(0);
	CreatePortalMessage* ptr = new CreatePortalMessage(0, GetPosition().x, GetPosition().y);
	ptr->QueueMessage();
	SetPlayerNextLevel();
	Boss::SaveHighScore();
}

/*virtual*/ void Dragon::HandleEvent(const SGD::Event* pEvent) /*override*/
{
	if (pEvent->GetEventID() == "TODO")
	{
		
	}
	else
		MovingObject::HandleEvent(pEvent);
}

void Dragon::HandleCollision(GameObject* pOther)
{
	if (pOther->GetType() == MovingObject::OBJ_BULLET)
	{
		// don't shoot yourself
		if (((Projectile *)pOther)->GetOwner() == this) return;

		// call MovingObjects HandleCollision
		MovingObject::HandleCollision(pOther);
		// play hit sfx
		SGD::AudioManager::GetInstance()->PlayAudio(damageAudio);
	}

	CharacterCollision(pOther);
}
